﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Controls;
using System.Windows;
using System.Diagnostics;
using System.Windows.Controls.Primitives;
using System.Windows.Markup;
using System.Collections;
using System.Windows.Media;
using System.Windows.Media.Animation;

namespace WPFIPodControls
{
    /// <summary>
    /// page scroller like IPod touch
    /// </summary>
    public partial class IPodPageScroller : ItemsControl
    {
        DataTemplate _defaultDataTemplate;
        ContentPresenter _invisiblePresenter;
        ContentPresenter _visiblePresenter;
        int _animationCount = 0;

        public IPodPageScroller() 
        {
            //Width = 188.448;//320;
            //Height = 282.672;//480;
            _currentIndex = -1;
            InitializeComponent();
        }

        private void OnLoaded(object sender, RoutedEventArgs args)
        {
            _defaultDataTemplate = FindResource("defaultDataTemplate") as DataTemplate;
            _visiblePresenter = GetTemplateChild("p1") as ContentPresenter;
            _invisiblePresenter = GetTemplateChild("p2") as ContentPresenter;

            BindContent();
        }

        protected override void OnItemsChanged(System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            base.OnItemsChanged(e);
            if (!CurrentIndexChecked())
            {
                BindContent();
            }
        }

        private bool CurrentIndexChecked()
        {
            int cnt = ItemsCount;
            if (!(_currentIndex >= 0 && _currentIndex < cnt))
            {
                if (_currentIndex >= cnt)
                {
                    CurrentIndex = cnt - 1;
                }
                else
                {
                    CurrentIndex = 0;
                }
                return true;
            }
            return false;
        }

        private void BindContent()
        {
            ContentPresenter p1 = _visiblePresenter;
            if (p1 == null)
                return;
            DataTemplate dt = ItemTemplate;
            if (dt == null)
                dt = _defaultDataTemplate;

            p1.ContentTemplate = dt;
            p1.Content = CurrentItem;
        }

        private int ItemsCount
        {
            get
            {
                if (ItemsSource != null)
                {
                    if (ItemsSource is ICollection)
                        return (ItemsSource as ICollection).Count;
                    int count = 0;
                    foreach (object o in ItemsSource) 
                        count++;
                    return count;
                }
                return Items.Count;
            }
        }

        private int _currentIndex = 0;

        public int CurrentIndex
        {
            get
            {
                return _currentIndex;
            }
            set
            {
                if (value != _currentIndex)
                {
                    if (value >= 0 && value < ItemsCount)
                    {
                        int oldIndex = _currentIndex;
                        _currentIndex = value;
                        AnimateFrom(oldIndex, ScrollingDuration);
                    }
                }
            }
        }

        /// <summary>
        /// animation management
        /// </summary>
        /// <param name="oldIndex"></param>
        /// <param name="msDuration"></param>
        private void AnimateFrom(int oldIndex, int msDuration)
        {
            if (_visiblePresenter == null)
                return;
            int multiply = oldIndex <= _currentIndex ? 1 : -1;
            if (true)
            {
                _animationCount++;
                int currentAnim = _animationCount;
                
                _invisiblePresenter.BeginAnimation(FrameworkElement.MarginProperty, null);
                _visiblePresenter.BeginAnimation(FrameworkElement.MarginProperty, null);

                ContentPresenter tmp = _invisiblePresenter;
                _invisiblePresenter = _visiblePresenter;
                _visiblePresenter = tmp;
                _visiblePresenter.Visibility = Visibility.Hidden;
                //bind on invisible part, before showing
                BindContent();               

                ThicknessAnimation anim = new ThicknessAnimation();
                anim.From = new Thickness(0);
                anim.To = new Thickness(-multiply * this.ActualWidth, 0, multiply * this.ActualWidth, 0);
                anim.Duration = new Duration(TimeSpan.FromMilliseconds(msDuration));
                anim.AccelerationRatio = 0.6;
                anim.Completed += delegate
                {
                    //to prevent several nextPage before animation ends
                    if (currentAnim == _animationCount)
                    {
                        _animationCount = 0;
                        _invisiblePresenter.Visibility = Visibility.Collapsed;
                    }

                };
                ThicknessAnimation anim1 = new ThicknessAnimation();
                anim1.From = new Thickness(multiply * this.ActualWidth, 0, -multiply * this.ActualWidth, 0);
                anim1.To = new Thickness(0);
                anim1.Duration = new Duration(TimeSpan.FromMilliseconds(msDuration));
                anim1.AccelerationRatio = 0.6;

                _invisiblePresenter.BeginAnimation(FrameworkElement.MarginProperty, anim);
                _visiblePresenter.BeginAnimation(FrameworkElement.MarginProperty, anim1);
                _visiblePresenter.Visibility = Visibility.Visible;
            }
        }

        private object CurrentItem
        {
            get
            {
                if (_currentIndex >= 0 && _currentIndex < Items.Count)
                {
                    return Items[_currentIndex];
                }
                return null;
            }
        }

        public void ScrollNextPage()
        {
            CurrentIndex = CurrentIndex + 1;
        }

        public void ScrollPreviousPage()
        {
            CurrentIndex = CurrentIndex - 1;
        }

        public void ScrollToPage(int index)
        {
            CurrentIndex = index;
        }



        public int ScrollingDuration
        {
            get { return (int)GetValue(ScrollingDurationProperty); }
            set { SetValue(ScrollingDurationProperty, value); }
        }

        // Using a DependencyProperty as the backing store for ScrollingDuration.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ScrollingDurationProperty =
            DependencyProperty.Register("ScrollingDuration", typeof(int), typeof(IPodPageScroller), new UIPropertyMetadata(250));


    }
}
